package com.xc.disk.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.xc.disk.bean.ForgetBean;
import com.xc.disk.bean.LoginBean;
import com.xc.disk.bean.RegisterBean;
import com.xc.disk.config.Constants;
import com.xc.disk.dto.LoginDto;
import com.xc.disk.dto.UserDto;
import com.xc.disk.dto.VerifyAccountDto;
import com.xc.disk.entity.UserEntity;
import com.xc.disk.exception.OperateException;
import com.xc.disk.info.TokenInfo;
import com.xc.disk.mapper.UserMapper;
import com.xc.disk.service.AuthorizeService;
import com.xc.disk.utils.RedisUtils;
import com.xc.tool.utils.JSONUtils;
import com.xc.tool.utils.Md5Utils;
import com.xc.tool.utils.ObjectUtils;
import com.xc.tool.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * <p>项目名称: Stars</p>
 * <p>描述: 授权实现</p>
 * <P>创建人:小程 </p>
 * <P>创建人邮箱: 779943476@qq.com</p>
 * <p>创建时间: 2019/10/24</p>
 *
 * @version v1.0
 */
@Service
public class AuthorizeServiceImpl implements AuthorizeService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private Constants constants;

    @Override
    public LoginDto login(LoginBean loginBean, String clientIp) {
        if (loginBean.getAccount() == null) {
            throw new OperateException("f029", "账号不能为空！");
        }
        UserEntity userEntity = new UserEntity();
        userEntity.setAccount(loginBean.getAccount());
        UserEntity user = userMapper.selectOne(new QueryWrapper<>(userEntity));
        if (user == null) {
            throw new OperateException("f001", "账户信息不存在！");
        }
        //是否需要验证码
        if (user.getFailRecord() >= constants.getOpenVerifyCodeNum()) {
            if (loginBean.getCode() == null) {
                throw new OperateException("f003", "code不能为空！");
            }
            String code = RedisUtils.get(loginBean.getCode());
            RedisUtils.delete(loginBean.getCode());
            if (code == null || !code.toUpperCase().equals(loginBean.getVerifyCode().toUpperCase())) {
                throw new OperateException("f018", "验证码错误！");
            }
        }
        //账户已锁定
        if (user.getState() == 1) {
            throw new OperateException("f019", "账户已锁定，请联系管理员解锁!");
        }
        //密码错误次数达上限
        if (user.getFailRecord() >= constants.getPasswordErrorsNum()) {
            user.setState(1);
            if (userMapper.updateById(user) == 0) {
                throw new OperateException("f020", "操作用户数据失败!");
            }
            throw new OperateException("f021", "你输错的密码已达上限，账户已锁定，请联系我管理员解锁!");
        }
        //验证密码
        if (!Md5Utils.verifySaltMd5(loginBean.getPassword(), user.getPassword())) {
            user.setFailRecord(user.getFailRecord() + 1);
            if (userMapper.updateById(user) == 0) {
                throw new OperateException("f022", "操作用户数据失败!");
            }
            throw new OperateException("f023", "账户密码不正确！");
        }
        //重置密码错误次数
        if (user.getFailRecord() != 0) {
            user.setFailRecord(0);
            if (userMapper.updateById(user) == 0) {
                throw new OperateException("f024", "操作用户数据失败!");
            }
        }
        if (user.getToken() != null) {
            String json = RedisUtils.get(user.getToken());
            if (json != null) {
                RedisUtils.delete(user.getToken());
            }
        }
        LoginDto loginDto = getToken(user, clientIp);
        user.setToken(loginDto.getToken());
        if (userMapper.updateById(user) == 0) {
            throw new OperateException("f024", "操作用户数据失败!");
        }
        return loginDto;
    }

    @Override
    public TokenInfo<UserDto> updateToken(String token, String clientIp) {
        Map<String, Object> map = new HashMap<>();
        map.put("data", UserDto.class);
        TokenInfo<UserDto> tokenInfo = JSONUtils.getObjectByStringAndMap(RedisUtils.get(token),
                TokenInfo.class, map);
        if (tokenInfo == null) {
            throw new OperateException("a015", "你的登录已失效,请重新登录!");
        }
        if (!tokenInfo.getClientIp().equals(clientIp)) {
            throw new OperateException("a015", "你的登录已失效,请重新登录!");
        }
        if ((tokenInfo.getUpdateTime().getTime() + tokenInfo.getExpiryTime()) < new Date().getTime()) {
            throw new OperateException("a015", "你的登录已失效,请重新登录!");
        }
        tokenInfo.setUpdateTime(new Date());
        RedisUtils.set(token, JSONUtils.getStringByObject(tokenInfo), tokenInfo.getExpiryTime());
        return tokenInfo;
    }

    /**
     * 生成token
     *
     * @param user     用户信息
     * @param clientIp 客户端ip
     * @return 登录信息
     */
    private LoginDto getToken(UserEntity user, String clientIp) {
        //生成token
        final String token = Md5Utils.getSaltMd5(UUID.randomUUID().toString());
        //状态信息
        TokenInfo<UserDto> tokenInfo = new TokenInfo<>();
        tokenInfo.setUserId(user.getId());
        tokenInfo.setUpdateTime(new Date());
        tokenInfo.setExpiryTime(constants.getExpiryTime());
        tokenInfo.setData(ObjectUtils.convert(new UserDto(), user));
        tokenInfo.setToken(token);
        tokenInfo.setClientIp(clientIp);

        RedisUtils.set(token, JSONUtils.getStringByObject(tokenInfo), tokenInfo.getExpiryTime());
        //返回信息
        LoginDto loginDto = new LoginDto();
        loginDto.setCreateTime(new Date());
        loginDto.setToken(token);
        loginDto.setExpiryTime(constants.getExpiryTime());
        return loginDto;
    }


    @Override
    public void deleteToken(String token) {
        RedisUtils.delete(token);
    }

    @Override
    public LoginDto register(RegisterBean registerBean, String clientIp) {
        if (registerBean.getAccount() == null) {
            throw new OperateException("f029", "账号不能为空！");
        }
        String key = "register" + registerBean.getAccount();
        String code = RedisUtils.get(key);
        if (registerBean.getMailCode() != null && registerBean.getMailCode().equals(code)) {
            RedisUtils.delete(key);
            UserEntity userEntity = ObjectUtils.convert(new UserEntity(), registerBean);
            userEntity.setPassword(Md5Utils.getSaltMd5(registerBean.getPassword()));
            String appId = StringUtils.generateAccount(constants.getPrefix());
            userEntity.setAppId(appId);
            userEntity.setAppSecret(Md5Utils.getSaltMd5(appId));
            userEntity.setState(0);
            userEntity.setFreeFlow(1073741824l);
            userEntity.setCloudSpace(1073741824l);
            userEntity.setIntegral(0l);
            userEntity.setShareCode(Md5Utils.getSaltMd5(UUID.randomUUID().toString()));
            if (!SqlHelper.retBool(userMapper.insert(userEntity))) {
                throw new OperateException("c001", "添加失败！");
            }
            LoginDto loginDto = getToken(userEntity, clientIp);
            userEntity.setToken(loginDto.getToken());
            if (userMapper.updateById(userEntity) == 0) {
                throw new OperateException("f024", "操作用户数据失败!");
            }
            return loginDto;
        } else {
            throw new OperateException("f018", "验证码错误！");
        }
    }

    @Override
    public void forgetPassword(ForgetBean forgetBean) {
        if (forgetBean.getAccount() == null) {
            throw new OperateException("f029", "账号不能为空！");
        }
        String key = "forget" + forgetBean.getAccount();
        String code = RedisUtils.get(key);
        if (forgetBean.getMailCode() != null && forgetBean.getMailCode().equals(code)) {
            RedisUtils.delete(key);
            UserEntity userEntity = new UserEntity();
            userEntity.setAccount(forgetBean.getAccount());
            UserEntity userEntity1 = userMapper.selectOne(new QueryWrapper<>(userEntity));
            if (userEntity1 == null) {
                throw new OperateException("f001", "账户信息不存在！");
            }
            userEntity1.setPassword(Md5Utils.getSaltMd5(forgetBean.getPassword()));
            if (!SqlHelper.retBool(userMapper.updateById(userEntity1))) {
                throw new OperateException("c002", "修改失败！");
            }
        }
    }

    @Override
    public VerifyAccountDto verifyAccount(String account) {
        VerifyAccountDto verifyAccountDto = new VerifyAccountDto();
        UserEntity userEntity = new UserEntity();
        userEntity.setAccount(account);
        UserEntity userEntity1 = userMapper.selectOne(new QueryWrapper<>(userEntity));
        if (userEntity1 == null) {
            verifyAccountDto.setAccountCorrect(false);
        } else {
            verifyAccountDto.setAccountCorrect(true);
            if (userEntity1.getFailRecord() >= constants.getOpenVerifyCodeNum()) {
                verifyAccountDto.setOpenVerifyCode(true);
            } else {
                verifyAccountDto.setOpenVerifyCode(false);
            }
        }
        return verifyAccountDto;
    }
}
